﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using System.Diagnostics;
using System.ComponentModel;

namespace TextFlow.Activities
{
    [Designer( typeof( ActionSequenceActivityDesigner ) )]
	public class ActionSequenceActivity : SequenceActivity
	{
        private List<ActionInputActivity> _inputs = null;
        private List<ActionOutputActivity> _outputs = null;
        private Activity _action = null;

        public ActionSequenceActivity()
        {
        }

        public ActionSequenceActivity( string name ) : base( name )
        {
        }

        public string ConfiguredAction { get; set; }

        protected override ActivityExecutionStatus Execute( ActivityExecutionContext aec )
        {
            if ( this.EnabledActivities.Count == 0 )
            {
                return ActivityExecutionStatus.Closed;
            }
            else
            {
                Activity first = GetNextActivity( null );

                first.Closed += OnNextActivity;

                aec.ExecuteActivity( first );

                return ActivityExecutionStatus.Executing;
            }
        }

        private void OnNextActivity( object sender, ActivityExecutionStatusChangedEventArgs e )
        {
            ActivityExecutionContext aec = sender as ActivityExecutionContext;

            e.Activity.Closed -= OnNextActivity;

            Activity next = GetNextActivity( e.Activity );

            if ( next == null )
            {
                aec.CloseActivity();
            }
            else
            {
                next.Closed += OnNextActivity;

                aec.ExecuteActivity( next );
            }
        }

        private Activity GetNextActivity( Activity lastActivity )
        {
            if ( lastActivity == null )
            {
                if ( Inputs.Count > 0 )
                {
                    return Inputs[ 0 ];
                }
                else
                {
                    return Action;
                }
            }
            else if ( lastActivity is ActionInputActivity )
            {
                int idx = Inputs.IndexOf( lastActivity as ActionInputActivity );

                if ( idx == Inputs.Count - 1 )
                {
                    return Action;
                }
                else
                {
                    return Inputs[ idx + 1 ];
                }
            }
            else if ( object.ReferenceEquals( lastActivity, Action ) )
            {
                return Outputs.ElementAtOrDefault( 0 );
            }
            else
            {
                Debug.Assert( lastActivity is ActionOutputActivity );

                int idx = Outputs.IndexOf( lastActivity as ActionOutputActivity );

                return Outputs.ElementAtOrDefault( idx + 1 );
            }
        }

        internal List<ActionInputActivity> Inputs
        {
            get
            {
                if ( _inputs == null )
                {
                    _inputs = this.EnabledActivities.OfType<ActionInputActivity>().ToList();
                }

                return _inputs;
            }
        }

        internal List<ActionOutputActivity> Outputs
        {
            get
            {
                if ( _outputs == null )
                {
                    _outputs = this.EnabledActivities.OfType<ActionOutputActivity>().ToList();
                }

                return _outputs;
            }
        }

        internal Activity Action
        {
            get
            {
                if ( _action == null )
                {
                    var action = from child in this.EnabledActivities where !( child is ActionInputActivity ) && !( child is ActionOutputActivity ) select child;

                    if ( action.Count() == 0 )
                    {
                        throw new InvalidOperationException( "No action activity configured." );
                    }
                    else
                    {
                        Debug.Assert( action.Count() == 1 );

                        _action = action.ElementAt( 0 );
                    }
                }

                return _action;
            }
        }
    }
}
